image.png<template>
  <view class="requirement-edit-page tn-safe-area-inset-bottom">
    <!-- 顶部自定义导航 -->
    <view :style="{ height: vuex_custom_bar_height + 'px' }" class="tn-navbg">
      <tn-nav-bar customBack fixed backgroundColor="#ffffff">
        <view slot="back" class="tn-custom-nav-bar__back" @click="goBack">
          <text class="icon tn-icon-left"></text>
          <text class="icon tn-icon-home-capsule-fill"></text>
        </view>
        <view class="tn-flex tn-flex-col-center tn-flex-row-center">
          <text class="tn-text-bold tn-text-xl tn-color-black">编辑需求描述</text>
        </view>
        <view slot="right" class="tn-custom-nav-bar__right">
          <!-- 移除顶部保存按钮，避免重复 -->
        </view>
      </tn-nav-bar>
    </view>

    <!-- 页面实际内容 -->
    <view class="page">
      <view class="editor-container">
        <view class="editor-header">
          <text class="editor-title">需求描述</text>
         
        </view>
        
        <view class="editor-wrapper">
          <editor
            id="editor"
            class="editor"
            placeholder="请输入需求描述"
            show-img-size
            show-img-toolbar
            show-img-resize
            @ready="onEditorReady"
            @input="onEditorInput"
            @blur="onEditorBlur"
          ></editor>
        </view>
        
                 <view class="editor-toolbar">
           <view class="toolbar-left">
             <text class="char-count">当前字符数：{{ currentLength }}</text>
           </view>
           <view class="toolbar-right">
             <tn-button
               size="sm"
               backgroundColor="#F3F4F6"
               fontColor="#6B7280"
               :fontSize="24"
               @click="clearContent"
             >
               清空
             </tn-button>
             <tn-button
               size="lg"
               backgroundColor="#4B7BF5"
               fontColor="#FFFFFF"
               :fontSize="28"
               @click="saveContent"
               class="save-button"
             >
               保存
             </tn-button>
           </view>
         </view>
      </view>
    </view>
  </view>
</template>

<script>
import template_page_mixin from "@/libs/mixin/template_page_mixin";
import { marked } from 'marked';

export default {
  name: "RequirementEdit",
  mixins: [template_page_mixin],
  data() {
    return {
      content: "", // 编辑器的内容
      originalContent: "", // 原始内容，用于比较是否有变化
      editorCtx: null, // 编辑器上下文
      currentLength: 0, // 当前字符数
      hasChanges: false, // 是否有未保存的更改
    };
  },
  computed: {
    // 检查内容是否有变化
    contentChanged() {
      return this.content !== this.originalContent;
    }
  },
  methods: {
    // 初始化编辑器
    initEditor() {
      this.editorCtx = uni.createSelectorQuery()
        .select('#editor')
        .context(res => {
          this.editorCtx = res.context;
          // 设置编辑器内容
          if (this.content) {
            // 尝试将Markdown转换为HTML
            try {
              const html = marked(this.content);
              this.editorCtx.setContents({
                html: html
              });
            } catch (error) {
              console.error('Markdown转换失败:', error);
              // 如果转换失败，直接设置原始内容
              this.editorCtx.setContents({
                html: this.content
              });
            }
          }
        })
        .exec();
    },
    
    // 编辑器准备就绪
    onEditorReady() {
      this.initEditor();
    },
    
    // 编辑器内容变化
    onEditorInput(e) {
      // 获取编辑器内容
      if (this.editorCtx) {
        this.editorCtx.getContents({
          success: res => {
            const htmlContent = res.html || "";
            // 将HTML转换为Markdown格式来比较变化
            const markdownContent = this.convertHtmlToMarkdown(htmlContent);
            this.content = markdownContent;
            // 计算纯文本长度（去除HTML标签）
            this.currentLength = this.getTextLength(htmlContent);
            this.hasChanges = this.contentChanged;
          },
          fail: err => {
            console.error('获取编辑器内容失败:', err);
          }
        });
      }
    },
    
        // 编辑器失去焦点时也获取内容
    onEditorBlur() {
      this.onEditorInput();
    },
    
    // 获取纯文本长度
    getTextLength(html) {
      if (!html) return 0;
      // 移除HTML标签，获取纯文本
      const text = html.replace(/<[^>]*>/g, '');
      // 解码HTML实体
      const decoded = text
        .replace(/&nbsp;/g, ' ')
        .replace(/&amp;/g, '&')
        .replace(/&lt;/g, '<')
        .replace(/&gt;/g, '>')
        .replace(/&quot;/g, '"');
      return decoded.length;
    },
    
    // 清空内容
    clearContent() {
      uni.showModal({
        title: '确认清空',
        content: '确定要清空所有内容吗？',
        success: (res) => {
          if (res.confirm) {
            this.content = "";
            this.currentLength = 0;
            this.hasChanges = true;
            if (this.editorCtx) {
              this.editorCtx.setContents({
                html: ""
              });
            }
          }
        }
      });
    },
    
    // 保存内容
    async saveContent() {
      // 获取编辑器内容
      if (!this.editorCtx) {
        uni.showToast({
          icon: 'error',
          title: '编辑器未初始化'
        });
        return;
      }
      
      try {
        const htmlContent = await this.getEditorContent();
        
        // 检查内容是否为空
        if (!htmlContent.trim()) {
          uni.showToast({
            icon: 'error',
            title: '请输入需求描述内容'
          });
          return;
        }
        
        // 将HTML内容转换为Markdown格式保存
        const markdownContent = this.convertHtmlToMarkdown(htmlContent);
        
        // 保存Markdown格式的内容
        this.content = markdownContent;
        this.originalContent = markdownContent; // 更新原始内容，确保状态一致
        this.hasChanges = false;
        
        // 调试信息
        console.log('保存成功，状态更新：', {
          htmlContent: htmlContent,
          markdownContent: markdownContent,
          hasChanges: this.hasChanges
        });
        
        // 发送事件通知父页面内容已更新（发送Markdown格式）
        uni.$emit("requirementDescriptionUpdated", markdownContent);
        
        uni.showToast({
          icon: 'success',
          title: '保存成功'
        });
        
        // 延迟返回，让用户看到保存成功的提示
        setTimeout(() => {
          this.goBack();
        }, 1000);
        
      } catch (error) {
        console.error('保存内容失败:', error);
        uni.showToast({
          icon: 'error',
          title: '保存失败'
        });
      }
    },
    
    // 获取编辑器内容
    getEditorContent() {
      return new Promise((resolve, reject) => {
        this.editorCtx.getContents({
          success: res => {
            resolve(res.html || "");
          },
          fail: err => {
            console.error('获取编辑器内容失败:', err);
            reject(err);
          }
        });
      });
    },
    
    // 将HTML内容转换为Markdown格式
    convertHtmlToMarkdown(html) {
      if (!html) return '';
      
      let markdown = html;
      
      // 移除多余的空白字符
      markdown = markdown.replace(/\s+/g, ' ').trim();
      
      // 转换标题
      markdown = markdown.replace(/<h1[^>]*>(.*?)<\/h1>/gi, '# $1\n\n');
      markdown = markdown.replace(/<h2[^>]*>(.*?)<\/h2>/gi, '## $1\n\n');
      markdown = markdown.replace(/<h3[^>]*>(.*?)<\/h3>/gi, '### $1\n\n');
      markdown = markdown.replace(/<h4[^>]*>(.*?)<\/h4>/gi, '#### $1\n\n');
      markdown = markdown.replace(/<h5[^>]*>(.*?)<\/h5>/gi, '##### $1\n\n');
      markdown = markdown.replace(/<h6[^>]*>(.*?)<\/h6>/gi, '###### $1\n\n');
      
      // 转换粗体
      markdown = markdown.replace(/<(strong|b)[^>]*>(.*?)<\/(strong|b)>/gi, '**$2**');
      
      // 转换斜体
      markdown = markdown.replace(/<(em|i)[^>]*>(.*?)<\/(em|i)>/gi, '*$2*');
      
      // 转换行内代码
      markdown = markdown.replace(/<code[^>]*>(.*?)<\/code>/gi, '`$1`');
      
      // 转换代码块
      markdown = markdown.replace(/<pre[^>]*><code[^>]*>(.*?)<\/code><\/pre>/gi, '```\n$1\n```\n\n');
      
      // 转换分隔线
      markdown = markdown.replace(/<hr[^>]*>/gi, '\n---\n\n');
      
      // 转换无序列表
      markdown = markdown.replace(/<ul[^>]*>(.*?)<\/ul>/gi, (match, content) => {
        const items = content.replace(/<li[^>]*>(.*?)<\/li>/gi, '- $1\n');
        return '\n' + items + '\n';
      });
      
      // 转换有序列表
      markdown = markdown.replace(/<ol[^>]*>(.*?)<\/ol>/gi, (match, content) => {
        let counter = 1;
        const items = content.replace(/<li[^>]*>(.*?)<\/li>/gi, () => {
          return `${counter++}. $1\n`;
        });
        return '\n' + items + '\n';
      });
      
      // 转换段落
      markdown = markdown.replace(/<p[^>]*>(.*?)<\/p>/gi, '$1\n\n');
      
      // 转换换行
      markdown = markdown.replace(/<br[^>]*>/gi, '\n');
      
      // 移除其他HTML标签
      markdown = markdown.replace(/<[^>]*>/g, '');
      
      // 解码HTML实体
      markdown = markdown
        .replace(/&nbsp;/g, ' ')
        .replace(/&amp;/g, '&')
        .replace(/&lt;/g, '<')
        .replace(/&gt;/g, '>')
        .replace(/&quot;/g, '"')
        .replace(/&#39;/g, "'");
      
      // 清理多余的换行符
      markdown = markdown.replace(/\n{3,}/g, '\n\n');
      
      return markdown.trim();
    },
    
    // 返回上一页
    goBack() {
      // 调试信息
      console.log('goBack 调用，当前状态：', {
        hasChanges: this.hasChanges,
        content: this.content,
        originalContent: this.originalContent
      });
      
      // 如果有未保存的更改，提示用户
      if (this.hasChanges) {
        console.log('显示保存确认弹窗');
        uni.showModal({
          title: '提示',
          content: '有未保存的更改，确定要离开吗？',
          confirmText: '离开',
          cancelText: '保存',
          success: (res) => {
            if (res.confirm) {
              // 用户选择离开，直接返回
              console.log('用户选择离开，直接返回');
              uni.navigateBack();
            } else {
              // 用户选择保存，先保存再返回
              console.log('用户选择保存，调用保存方法');
              this.saveContent();
            }
          }
        });
      } else {
        // 没有未保存的更改，直接返回
        console.log('没有未保存的更改，直接返回');
        uni.navigateBack();
      }
    }
  },
  
  onLoad(option) {
    // 获取传递的参数
    const { content = "", id = "", mode = "" } = option;
    
    // 解码内容
    this.content = decodeURIComponent(content);
    this.originalContent = this.content;
    this.currentLength = this.getTextLength(this.content);
    
    // 保存其他参数到本地存储，以便后续使用
    uni.setStorageSync('requirementEditParams', { id, mode });
  },
  
  onReady() {
    // 延迟初始化编辑器，确保DOM已渲染
    setTimeout(() => {
      this.initEditor();
    }, 100);
  },
  
  // 页面显示时
  onShow() {
    // 可以在这里处理页面显示逻辑
  },
  
  // 页面隐藏时
  onHide() {
    // 可以在这里处理页面隐藏逻辑
  },
  
  // 页面卸载时
  onUnload() {
    // 清理资源
    this.editorCtx = null;
  },
  
  // 处理页面返回键
  onBackPress() {
    // 如果有未保存的更改，提示用户
    if (this.hasChanges) {
      uni.showModal({
        title: '提示',
        content: '有未保存的更改，确定要离开吗？',
        confirmText: '离开',
        cancelText: '保存',
        success: (res) => {
          if (res.confirm) {
            // 用户选择离开，直接返回
            uni.navigateBack();
          } else {
            // 用户选择保存，先保存再返回
            this.saveContent();
          }
        }
      });
      return true; // 阻止默认返回行为
    }
    // 没有未保存的更改，允许默认返回行为
    return false;
  }
};
</script>

<style lang="scss" scoped>
.requirement-edit-page {
  background-color: #f8fafc;
  min-height: 100vh;
  // 确保页面内容能够完整展示
  height: auto;
  overflow: visible;
}

.tn-navbg {
  background-color: #ffffff;
  position: relative;
  z-index: 9999;
  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.15);
  border-bottom: 1rpx solid #e5e7eb;
}

.tn-custom-nav-bar__back {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  justify-content: space-evenly;
  align-items: center;
  box-sizing: border-box;
  background-color: rgba(0, 0, 0, 0.15);
  border-radius: 1000rpx;
  border: 1rpx solid rgba(255, 255, 255, 0.5);
  color: #ffffff;
  font-size: 18px;

  .icon {
    display: block;
    flex: 1;
    margin: auto;
    text-align: center;
  }

  &:before {
    content: " ";
    width: 1rpx;
    height: 110%;
    position: absolute;
    top: 22.5%;
    left: 0;
    right: 0;
    margin: auto;
    transform: scale(0.5);
    transform-origin: 0 0;
    pointer-events: none;
    box-sizing: border-box;
    opacity: 0.7;
    background-color: #ffffff;
  }
}

.tn-custom-nav-bar__right {
  display: flex;
  align-items: center;
  height: 100%;
  min-width: 80rpx; /* 确保右侧区域有最小宽度，保持布局平衡 */
}

.page {
  margin: 0rpx 32rpx 30rpx 32rpx;
  padding-top: 20rpx;
  position: relative;
  z-index: 1;
  // 确保页面内容能够完整展示
  height: auto;
  overflow: visible;
}

.editor-container {
  background-color: #ffffff;
  border-radius: 16rpx;
  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
  // 移除overflow: hidden，允许内容完整展示
  overflow: visible;
}

.editor-header {
  padding: 32rpx 32rpx 24rpx 32rpx;
  border-bottom: 1rpx solid #f1f5f9;
  
  .editor-title {
    display: block;
    font-size: 32rpx;
    font-weight: 600;
    color: #1f2937;
    margin-bottom: 8rpx;
  }
  
  .editor-subtitle {
    display: block;
    font-size: 26rpx;
    color: #6b7280;
    line-height: 1.4;
  }
}

.editor-wrapper {
  padding: 0;
  
  .editor {
    width: 100%;
    min-height: 600rpx;
    background-color: #ffffff;
    padding: 24rpx 32rpx;
    box-sizing: border-box;
    font-size: 28rpx;
    line-height: 1.6;
    color: #374151;
    // 移除固定高度，允许内容自然展开
    height: auto;
    overflow: visible;
    // 确保编辑器能够适应内容高度
    resize: vertical;
  }
}

.editor-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 24rpx 32rpx;
  border-top: 1rpx solid #f1f5f9;
  background-color: #f9fafb;
  
  .toolbar-left {
    .char-count {
      font-size: 24rpx;
      color: #9ca3af;
      transition: color 0.3s ease;
    }
  }
  
  .toolbar-right {
    display: flex;
    gap: 16rpx;
    align-items: center;
    
    .save-button {
      min-width: 120rpx;
      box-shadow: 0 4rpx 12rpx rgba(75, 123, 245, 0.3);
      transition: all 0.3s ease;
      
      &:active {
        transform: translateY(2rpx);
        box-shadow: 0 2rpx 8rpx rgba(75, 123, 245, 0.3);
      }
    }
  }
}
</style> 